#ifndef __MCS__FUNCTION_SIGNATURE__HPP
#define __MCS__FUNCTION_SIGNATURE__HPP

#include "Value.hpp"

class FunctionSignature : public Void
{
public:
	FunctionSignature(String const & name)
		: Void()
		, name_(name)
	{
	}

	FunctionSignature(String const & name, size_t argCount)
		: Void()
		, name_(name)
	{
		argTypes_.reserve(argCount);
	}

	void addArgumentType(Value::DataType type)
	{
		argTypes_.push_back(type);
	}

	String const & name() const
	{
		return name_;
	}
	
	size_t argumentCount() const
	{
		return argTypes_.size();
	}
	
	Value::DataType argumentType(size_t i) const
	{
		return argTypes_.at(i);
	}
	
	std::vector<Value::DataType> const & argumentTypes() const
	{
		return argTypes_;
	}

	int compare(FunctionSignature const & other) const
	{
		int r = name_.compare(other.name_);
		if(r != 0) return r;

		if(argTypes_.size() < other.argTypes_.size()) return -1;
		if(argTypes_.size() > other.argTypes_.size()) return +1;

		for(size_t i=0; i<argTypes_.size(); ++i)
		{
			if(argTypes_.at(i) < other.argTypes_.at(i)) return -1;
			if(argTypes_.at(i) > other.argTypes_.at(i)) return +1;
		}
		return 0;
	}

	bool operator==(FunctionSignature const & other) const
	{
		return compare(other) == 0;
	}

	bool operator!=(FunctionSignature const & other) const
	{
		return compare(other) != 0;
	}

	bool operator<(FunctionSignature const & other) const
	{
		return compare(other) < 0;
	}

	bool operator>(FunctionSignature const & other) const
	{
		return compare(other) > 0;
	}

	bool operator<=(FunctionSignature const & other) const
	{
		return compare(other) <= 0;
	}

	bool operator>=(FunctionSignature const & other) const
	{
		return compare(other) >= 0;
	}
private:
	String name_;
	std::vector<Value::DataType> argTypes_;
};

inline std::ostream & operator<<(std::ostream & stream, FunctionSignature const & sig)
{
	stream << sig.name() << '(';
	for(size_t i=0; i<sig.argumentCount(); ++i)
	{
		if(i) stream << ',';
		stream << sig.argumentType(i);
	}
	stream << ')';
	return stream;
}

#endif //__MCS__FUNCTION_SIGNATURE__HPP
